\section{Лекция 14.02.2012. Параметры шаблонов и специализация}

\subsection{Параметры шаблонов}

\paragraph{Примеры параметров шаблонов:}
\begin{itemize}
\item
\begin{lstlisting}
template <class T>
\end{lstlisting}
самый простой способ шаблона

\item
\begin{lstlisting}
template <template <class> class T>
\end{lstlisting}
шаблон в качестве параметра принимает шаблонный тип, который мы можем инстанцировать конкретным типом уже внутри шаблона, т. е. параметр не является конкретным
типом.

\item
\begin{lstlisting}
template <int N>
\end{lstlisting}
где вместо $int$ может использоваться любой целочисленный тип или перечисление, каждый параметр должен быть известен на момент компиляции. Почему не допустимы
вещественные числа? Потому что, в компьютере вещественные числа считаются не точно, и даже самые простые преобразования могут приводить к конфузам.

\item Параметрами шаблонов могут быть указатели и ссылки, которые должны иметь внешнее связывание (указатель на глобальную переменную, например):
\begin{lstlisting}
template <int *p>
\end{lstlisting}

\item Указатели на всякие другие сущности (функции, поля классов и много другое).
\end{itemize}

\subsection{Специализация шаблонов}

Класический пример специализации шаблонов: допустим имеется необходимость использовать некоторый массив (контейнер) элементов типа $bool$, как это сделать?
Очевидный ответ:
\begin{lstlisting}
bool m[100];
\end{lstlisting}
какого размера будет этот массив? Ответ не меньше 100 байт, но это очевидно перебор, как сделать это более разумным способом?
\begin{lstlisting}
template <class T>
struct Array {
	T *data;
}
\end{lstlisting}
допустим имеется шаблон описанный выше, как заставить работать его с битами разумнее? Ответ специализировать его для конктерного типа $bool$:
\begin{lstlisting}
template <>
struct Array<bool> {
	int *data;
}
\end{lstlisting}
т. е. мы не доверяем компилятору специализацию шаблона для конктерного типа ($bool$ в данном случае), а берем ее на себя и описываем ее самостоятельно. Аналогчным
образом можно описать специализацию функции:
\begin{lstlisting}
template <class T>
void reverse(Array<T> a) {
	...
}

template <>
void reverse(Array<bool> a) {
	...
}
\end{lstlisting}

\paragraph{Примечания:} к моменту специализации шаблон должен быть известен (но не обязательно моежт быть известно определение шаблона)
\begin{lstlisting}
template <class T>
struct Array;

template <>
struct Array<bool> {
	int *data;
}
\end{lstlisting}

\subsection{Частичная специализация шаблона}

\begin{lstlisting}
template <class T>
struct Array;

template <class U>
struct Array<U*> {
	...
}
\end{lstlisting}
выше пример частичной специализации шаблона для работы с указателями, другой пример, специализация одного (нескольких) параметров шаблона:
\begin{lstlisting}
template <class A, class B>
struct Array;

template <class A, class B>
struct Array<Pair<A,B> >
\end{lstlisting}
здесь мы специализировали первый параметр шаблона.

Произведя частичную специализацию мы не получаем конкретный тип, мы вновь получаем шаблон, который необходимо инстанцировать. Кроме того частичной специализации
не может быть для функции. Почему? Потому что у объектов нет механизма перегрузки, т. е. для функций нет необходимости делать частичную специализацию, когда
можно воспользоваться перегрузкой, например, так:
\begin{lstlisting}
template <class T>
void reverse(Array<T> a);

template <class T>
void reverse(Array<T*> a);
\end{lstlisting}

\paragraph{Различия между между шаблонами функций и классов}

Шаблоны функций и шаблоны классов отличаются по ряду признаков, например, шаблоны классов имееют частиную специализацию и значения по умолчанию, а шаблоны
функций имееют перегрузку и вывод параметров (deducing). Пример параметра по-умолчанию:
\begin{lstlisting}
template <class T, class A = allocator<T> >
struct Array;
\end{lstlisting}
параметры по-умолчанию работают более или менее одинаково с параметрами по-умолчанию у функций.

\paragraph{Зависимые имена:}
\begin{lstlisting}
template <class T>
void f(Array<T> a) {
	Array<T>::allocator ... //(1)
	....
}
\end{lstlisting}
чтобы компмилятор понял, что (1) - обращение к типу необходимо писать следующим образом (некоторые компиляторы умеют угадывать тип в этом случае):
\begin{lstlisting}
template <class T>
void f(Array<T> a) {
	typename Array<T>::allocator ...
	....
}
\end{lstlisting}